package pap;

import java.util.concurrent.LinkedBlockingDeque;

import pap.bodies.BodiesManager;
import pap.bodies.Body;
import pap.tasks.CollisionChecker;
import pap.tasks.ForceCalculator;
import pap.tasks.PositionUpdater;
import pap.utils.Constants;

public class ComputationSystem {
	TimesRegister timesRegister;
	PositionUpdater positionUpdater;
	ForceCalculator forceCalculator;
	CollisionChecker collisionChecker;
	NamedThreadFactory fC, pU, cC;

	public ComputationSystem(TimesRegister timesRegister) {
		this.timesRegister = timesRegister;
		fC = new NamedThreadFactory("ForceCalculator");
		pU = new NamedThreadFactory("PositionUpdater");
		cC = new NamedThreadFactory("CollisionChecker");
	}

	/**
	 * Initializes and starts the system. The initialization can be done
	 * randomly or with a file.
	 * 
	 * @param timesRegister
	 */
	public void startSystem() {

		BufferManager.init(5, timesRegister);

		BodiesManager.initRandom();
		// BodiesManager.initFromFile("bodies.json");
		BodiesManager bodiesManager = BodiesManager.getInstance();

		LinkedBlockingDeque<Body> fcToPuList = new LinkedBlockingDeque<Body>();
		SynchronizedCounter ccToFcCounter = new SynchronizedCounter(
				bodiesManager.getBodiesCount());

		// The collisionChecker must be blocked at the system startup, so the
		// counter should be equal to zero
		SynchronizedCounter puToCc = new SynchronizedCounter(0);

		forceCalculator = new ForceCalculator(Constants.FC_THREADS, fcToPuList,
				bodiesManager, ccToFcCounter, fC);
		positionUpdater = new PositionUpdater(Constants.PU_THREADS, fcToPuList,
				bodiesManager, puToCc, BufferManager.getInstance(), pU);
		collisionChecker = new CollisionChecker(Constants.CC_THREADS,
				bodiesManager, puToCc, ccToFcCounter, cC);

		forceCalculator.start();
		positionUpdater.start();
		collisionChecker.start();
	}
}
